﻿/*
* This file is part of WinMergeFS.
*
* WinMergeFS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.

* WinMergeFS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WinMergeFS.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using WinMergeFS.Common;
using WinMergeFS.API;
using System.Text.RegularExpressions;

namespace WinMergeFS.W32
{
    class Mounter
    {
        public WinMergeFS.API.WinMergeFS mfs;
        private WinMergeFS.W32.LogHandler loghandler;
        public Mounter()
        {
            mfs = new WinMergeFS.API.WinMergeFS();
            loghandler = new WinMergeFS.W32.LogHandler();
            mfs.Logger += new WinMergeFS.Common.LoggerEventHandler(loghandler.doLogging);
        }


        public bool mountService()
        {
            return mountService(null);
        }

        // return true if success, else false
        public bool mountService(CommandLineArguments cmdline)
        {
            DataSet x = GetDataSet();
            string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
            x.ReadXml(path + "\\config.xml");
            try
            {
                loghandler.logfile = (string)x.Tables["general"].Rows[0]["logfile"];
            }
            catch (Exception)
            {
                loghandler.logfile = "none";
            }

            try
            {
                loghandler.loglevel = (LogLevel)Enum.Parse(typeof(LogLevel), (string)x.Tables["general"].Rows[0]["loglevel"], true);
            }
            catch (Exception)
            {
                loghandler.loglevel = LogLevel.info;
            }


            if (cmdline != null)
            {
                if (cmdline["logfile"] != null && cmdline["logfile"] != "true") loghandler.logfile = cmdline["logfile"];
                if (cmdline["loglevel"] != null && cmdline["loglevel"] != "true") loghandler.loglevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdline["loglevel"].ToLower());
            }


            try
            {
                for (int i = 0; i < x.Tables["profiles"].Rows.Count; i++)
                {
                    loghandler.doLogging("Mounting " + x.Tables["profiles"].Rows[i]["path"], LogLevel.info);
                    Profile profile = ProfileManager.LoadProfileFromFile((string)x.Tables["profiles"].Rows[i]["path"]);
                    if (profile != null)
                    {
                        PrintSummary(profile);
                        //System.Threading.Thread.Sleep(2000);
                        mfs.MountDrive(profile);
                    }
                }
                return true;
            }
            catch (Exception) { return false; }
        }


        // return true if success, else false
        public bool mountProfile(CommandLineArguments cmdline)
        {
            try
            {
                Profile profile = WinMergeFS.API.ProfileManager.LoadProfileFromFile(cmdline["profile"]);
                if (profile == null) return false;

                if (cmdline["logfile"] != null && cmdline["logfile"] != "true") loghandler.logfile = cmdline["logfile"];
                else loghandler.logfile = "console";

                if (cmdline["loglevel"] != null && cmdline["loglevel"] != "true") loghandler.loglevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdline["loglevel"].ToLower());
                else loghandler.loglevel = LogLevel.info;

                // give user the ability to override profile settings
                if (cmdline["volumeid"] != null && cmdline["volumeid"] != "true") profile.VolumeID = cmdline["volumeid"];
                if (cmdline["driveletter"] != null && cmdline["driveletter"] != "true") profile.DriveLetter = cmdline["driveletter"][0];


                // print summary 
                PrintSummary(profile);

                // mount the profily
                mfs.MountDrive(profile);

                return true;
            }
            catch (Exception) { return false; }
        }

        public Profile createProfile(CommandLineArguments cmdline)
        {
            if (((cmdline["roots"] == null || cmdline["roots"] == "true") && (cmdline["rroots"] == null || cmdline["rroots"] == "true"))
                        || (cmdline["driveletter"] == null) || (cmdline["driveletter"] == "true"))
            {
                Console.Error.Write("Not enough parameters. You need specify at least one -root or -rroot and -driveletter");
                return null;
            }
            else
            {
                List<RootEntry> roots = new List<RootEntry>();

                Regex reg = new Regex(@"::", RegexOptions.IgnoreCase);
                Regex reg2 = new Regex(@",", RegexOptions.IgnoreCase);

                // add roots
                if (cmdline["roots"] != null && cmdline["roots"] != "true")
                {
                    string[] rootarray = reg.Split(cmdline["roots"]);
                    for (int i = 0; i < rootarray.Length; i++)
                    {
                        roots.Add(new RootEntry(rootarray[i], false));
                    }
                }

                // add read only roots
                if (cmdline["rroots"] != null && cmdline["rroots"] != "true")
                {
                    string[] rootarray = reg.Split(cmdline["rroots"]);
                    for (int i = 0; i < rootarray.Length; i++)
                    {
                        roots.Add(new RootEntry(rootarray[i], true));
                    }
                }

                // add plugins
                Dictionary<string, ProfilePluginEntry> plugins = new Dictionary<string, ProfilePluginEntry>();

                if (cmdline["plugins"] != null && cmdline["plugins"] != "true")
                {
                    string[] pluginarray = reg.Split(cmdline["plugins"]);
                    for (int i = 0; i < pluginarray.Length; i++)
                    {
                        string[] pluginspecific = reg2.Split(pluginarray[i]);

                        // System.Globalization.CultureInfo.InvariantCulture.NumberFormat makes "." to be the decimal separator
                        if (pluginspecific.Length == 3) plugins.Add(pluginspecific[0], new ProfilePluginEntry(pluginspecific[0], i, System.Int32.Parse(pluginspecific[1]), System.Int32.Parse(pluginspecific[2])));
                        else
                        {
                            Console.Error.Write("Invalid plugin entry, must be \"pluginid,multiply,parameter\"");
                            return null;
                        }

                    }
                }
                else // if user doesnt specify any plugins, add diskspace by default (no files can be written otherwise)
                {
                    plugins.Add("diskspace", new ProfilePluginEntry("diskspace", 0, 100, 0));
                }


                string volumeid;
                if (cmdline["volumeid"] != null && cmdline["volumeid"] != "true") volumeid = cmdline["volumeid"];
                else volumeid = "WinMergeFS";
                char driveletter = cmdline["driveletter"][0];
                string description = driveletter.ToString();

                Profile profile = WinMergeFS.API.ProfileManager.NewProfile(description, volumeid, driveletter, roots, plugins);


                if (cmdline["logfile"] != null && cmdline["logfile"] != "true") loghandler.logfile = cmdline["logfile"];
                else loghandler.logfile = "console";

                if (cmdline["loglevel"] != null && cmdline["loglevel"] != "true") loghandler.loglevel = (LogLevel)Enum.Parse(typeof(LogLevel), cmdline["loglevel"].ToLower());
                else loghandler.loglevel = LogLevel.info;
                return profile;
            }
        }


        // return true if success, else false
        public bool mountManual(CommandLineArguments cmdline)
        {
            try
            {
                Profile profile = createProfile(cmdline);
                if (profile != null)
                {
                    // give the user a summery of what we are doing next
                    PrintSummary(profile);

                    // mount the profile
                    mfs.MountDrive(profile);
                }
                return true;
            }
            catch (Exception) { return false; }
        }

        public void unmountAll()
        {
            loghandler.doLogging("Unmounting all devices", LogLevel.info);
            mfs.UnmountAll();
        }

        public static DataSet GetDataSet()
        {
            DataSet x = new DataSet();
            x.Tables.Add("general");
            x.Tables.Add("profiles");
            x.Tables["general"].Columns.Add("logfile", System.Type.GetType("System.String"));
            x.Tables["general"].Columns.Add("loglevel", System.Type.GetType("System.String"));
            x.Tables["profiles"].Columns.Add("path", System.Type.GetType("System.String"));
            return x;
        }

        private void PrintSummary(Profile profile)
        {
            loghandler.doLogging("Profile summary:", LogLevel.info);
            loghandler.doLogging("Settings: Driveletter=" + profile.DriveLetter + ", volumeid=" + profile.VolumeID, LogLevel.info);

            foreach (RootEntry x in profile.Roots)
            {
                loghandler.doLogging("Settings: Root=" + x.RootPath + ", Readonly=" + x.ReadOnly.ToString(), LogLevel.info);
            }
            foreach (ProfilePluginEntry x in profile.Plugins.Values)
            {
                loghandler.doLogging("Settings: Plugin=" + x.PluginID + ", Multiply=" + x.Multiply + ", Parameter=" + x.Parameter, LogLevel.info);
            }
        }



    }
}
